<?php
declare(strict_types=1);

namespace LiLei\Logs;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;

class MyMonoLog
{
    // 日志所在 project_root/monolog/
    // $MyMonoLog->channel(string $channel)->info(string|array $message);
    // $MyMonoLog->write(string $channel, string|array $message);
    // 输出日志 monolog/command_20211218.log：[2021-12-18 15:55:50] debug.DEBUG: test debug.

    // 日志级别
    const DEBUG     = 'debug';
    // 信息
    const INFO      = 'info';
    // 注意
    const NOTICE    = 'notice';
    // 警告
    const WARNING   = 'warning';
    // 错误
    const ERROR     = 'error';
    // 关键的
    const CRITICAL  = 'critical';
    // 预警
    const ALERT     = 'alert';
    // 突发事件
    const EMERGENCY = 'emergency';

    /**
     * @var string 日志通道
     */
    private $channel = "info";

    /**
     * @var string 时间格式
     */
    private $dateFormat = "Y-m-d H:i:s";

    /**
     * @var string 输出格式
     */
    private $output = "[%datetime%] %channel%.%level_name%: %message% %context%\n";

    /**
     * @var string 日志目录
     */
    private $dirname = "";

    /**
     * 设置日志目录
     * 目录在 project_root 下，自己设置，例："storage/logs"
     *
     * @param string $dirname "monolog"
     * @return $this
     */
    public function setDirname(string $dirname = "monolog")
    {
        $search = "/vendor/lilei/my-mono-log/src";
        // project_root/vendor/lilei/my-mono-log/src/MyMonoLog.php
        $dir    = dirname(__FILE__);
        $dir    = str_replace("\\", "/", $dir);
        $dir    = str_replace($search, "", $dir);
        //var_dump($dir);

        $this->dirname = $dir .'/'. $dirname;

        return $this;
    }// setDirname() end

    /**
     * 日志目录
     * 
     * @return string
     */
    public function getDirname()
    {
        // 如果 dirname 是未设置，则使用初始目录
        if (1 > strlen($this->dirname)) $this->setDirname();

        return $this->dirname;
    }// getDirname() end

    /**
     * @param string $channel   日志文件名称
     * @return $this
     */
    public function channel(string $channel)
    {
        $this->setChannel($channel);

        return $this;
    }// channel() end

    /**
     * @param string $channel
     * @return $this
     */
    public function setChannel(string $channel)
    {
        $this->channel = $channel;

        return $this;
    }// setChannel() end

    /**
     * @return string
     */
    public function getChannel(): string
    {
        return $this->channel;
    }// getChannel() end

    /**
     * @param string $channel
     * @return string
     */
    public function generateFilename(string $channel): string
    {
        // dirname/202112/20/xxx-info-20211001.log
        return $this->getDirname().'/'.date('Ym').'/'.date('d')."/{$channel}_" . date('Ymd'). '.log';
    }// generateFilename() end

    /**
     * 格式化日志
     *
     * @return LineFormatter
     */
    public function getFormatter()
    {
        return new LineFormatter($this->output, $this->dateFormat);
    }// getFormatter() end

    /**
     * 获取处理流程
     *
     * @param string $log_file
     * @param string $level
     * @return StreamHandler
     */
    public function getStreamHandler(string $log_file, string $level)
    {
        $streamHandler = new StreamHandler($log_file, $level);
        $streamHandler->setFormatter($this->getFormatter());

        return $streamHandler;
    }// getStreamHandler() end

    /**
     * @param string        $channel   日志文件名称
     * @param string|array  $message
     */
    public function write(string $channel, $message)
    {
        $log_file = $this->generateFilename($channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger($this->getChannel());
        $logger->pushHandler($this->getStreamHandler($log_file, $this->getChannel()));
        $logger->info(str_replace("\\/", "/", $message));
    }// write() end

    /**
     * @param string|array $message
     */
    public function debug($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::DEBUG);
        $logger->pushHandler($this->getStreamHandler($log_file, self::DEBUG));
        $logger->debug(str_replace("\\/", "/", $message));
    }// debug() end

    /**
     * @param string|array $message
     */
    public function info($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::INFO);
        $logger->pushHandler($this->getStreamHandler($log_file, self::INFO));
        $logger->info(str_replace("\\/", "/", $message));
    }// info() end

    /**
     * @param string|array $message
     */
    public function notice($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::NOTICE);
        $logger->pushHandler($this->getStreamHandler($log_file, self::NOTICE));
        $logger->notice(str_replace("\\/", "/", $message));
    }// notice() end

    /**
     * @param string|array $message
     */
    public function warning($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::WARNING);
        $logger->pushHandler($this->getStreamHandler($log_file, self::WARNING));
        $logger->warning(str_replace("\\/", "/", $message));
    }// warning() end

    /**
     * @param string|array $message
     */
    public function error($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::ERROR);
        $logger->pushHandler($this->getStreamHandler($log_file, self::ERROR));
        $logger->error(str_replace("\\/", "/", $message));
    }// error() end

    /**
     * @param string|array $message
     */
    public function critical($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::CRITICAL);
        $logger->pushHandler($this->getStreamHandler($log_file, self::CRITICAL));
        $logger->critical(str_replace("\\/", "/", $message));
    }// critical() end

    /**
     * @param string|array $message
     */
    public function alert($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::ALERT);
        $logger->pushHandler($this->getStreamHandler($log_file, self::ALERT));
        $logger->alert(str_replace("\\/", "/", $message));
    }// alert() end

    /**
     * @param string|array $message
     */
    public function emergency($message)
    {
        $log_file = $this->generateFilename($this->channel);
        if (is_array($message)) $message = json_encode($message, JSON_UNESCAPED_UNICODE);

        $logger = new Logger(self::EMERGENCY);
        $logger->pushHandler($this->getStreamHandler($log_file, self::EMERGENCY));
        $logger->emergency(str_replace("\\/", "/", $message));
    }// emergency() end
}